package com.supermap.shiro.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.*;
import java.net.*;

/**
 * @author xiaolu
 * @date 2018/7/3 下午2:41
 */
public class HttpRequest {

    private final static int STATUS_SUCCESS = 200;

    /**
     * 发送HTTP请求并获取返回结果，此接口主要用于GET请求，
     * POST请求默认设置ContentType为application/x-www-form-urlencoded
     *
     * @param url          请求URL
     * @param method       请求方式
     * @param serializable 参数
     * @return 请求返回结果数据
     */
    public static JSONObject sentHttpRequest(String url, RequestMethod method, Serializable serializable) {
        return sentHttpRequest(url, method, serializable, ContentType.APPLICATION_X_WWW_FORM_URLENCODED);
    }

    /**
     * 发送HTTP请求并获取返回结果，此接口主要用于POST请求，
     * GET请求不会设置ContentType
     *
     * @param url          请求URL
     * @param method       请求方式
     * @param serializable 参数
     * @param contentType  ContentType
     * @return 请求返回结果数据
     */
    public static JSONObject sentHttpRequest(String url, RequestMethod method, Serializable serializable, ContentType contentType) {
        String result;
        JSONObject resultJson;
        if (method == RequestMethod.POST) {
            result = doPost(url, serializable, contentType);
        } else {
            result = doGet(url);
        }
        try {
            resultJson = JSON.parseObject(result);
        } catch (JSONException ex) {
            resultJson = new JSONObject();
            resultJson.put("data", result);
        }
        return resultJson;
    }

    /**
     * 发送GET请求
     *
     * @param httpUrl 请求URL
     * @return 返回结果数据
     */
    private static String doGet(String httpUrl) {
        HttpURLConnection connection = null;

        // 返回结果字符串
        String result = null;
        try {
            connection = getDefaultConnection(httpUrl, RequestMethod.GET);
            // 发送请求
            connection.connect();
            // 通过connection连接，获取输入流
            if (connection.getResponseCode() == STATUS_SUCCESS) {
                result = getHttpRequestResult(connection);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭远程连接
            assert connection != null;
            connection.disconnect();
        }

        return result;
    }

    /**
     * 发送POST请求
     *
     * @param httpUrl     请求URL
     * @param param       参数
     * @param contentType ContentType
     * @return 返回结果数据
     */
    private static String doPost(String httpUrl, Serializable param, ContentType contentType) {
        String paramStr = getPostParam(param, contentType);
        HttpURLConnection connection = null;
        OutputStream os = null;
        String result = null;
        try {
            connection = getDefaultConnection(httpUrl, RequestMethod.POST, contentType);
            // 通过连接对象获取一个输出流
            os = connection.getOutputStream();
            // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的
            os.write(paramStr.getBytes());
            // 通过连接对象获取一个输入流，向远程读取
            if (connection.getResponseCode() == STATUS_SUCCESS) {
                result = getHttpRequestResult(connection);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 断开与远程地址url的连接
            assert connection != null;
            connection.disconnect();
        }
        return result;
    }

    /**
     * 设置并获取请求连接
     *
     * @param httpUrl 请求URL
     * @param method  请求方法：POST/GET
     * @return HTTP连接对象
     * @throws IOException 远程连接异常
     */
    private static HttpURLConnection getDefaultConnection(String httpUrl, RequestMethod method) throws IOException {
        return getDefaultConnection(httpUrl, method, ContentType.APPLICATION_X_WWW_FORM_URLENCODED);
    }

    /**
     * 设置并获取请求连接
     *
     * @param httpUrl     请求URL
     * @param method      请求方法：POST/GET
     * @param contentType ContentType
     * @return HTTP连接对象
     * @throws IOException 远程连接异常
     */
    private static HttpURLConnection getDefaultConnection(String httpUrl, RequestMethod method, ContentType contentType) throws IOException {

        URL url = new URL(httpUrl);
        // 通过远程url连接对象打开连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // 设置连接请求方式
        connection.setRequestMethod(method.name());
        // 设置连接主机服务器超时时间：15000毫秒
        connection.setConnectTimeout(15000);
        // 设置读取主机服务器返回数据超时时间：60000毫秒
        connection.setReadTimeout(60000);

        if (method == RequestMethod.GET) {
            return connection;
        }

        // 默认值为：false，当向远程服务器传送数据/写数据时，需要设置为true
        connection.setDoOutput(true);
        // 默认值为：true，当前向远程服务读取数据时，设置为true，该参数可有可无
        connection.setDoInput(true);
        // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。
        connection.setRequestProperty("Content-Type", contentType.getDesc());
        // 设置鉴权信息：Authorization: Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0
        connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
        return connection;
    }

    /**
     * 根据contentType构造POST传参
     *
     * @param param       参数
     * @param contentType ContentType
     * @return
     */
    private static String getPostParam(Serializable param, ContentType contentType) {
        StringBuffer paramStr = new StringBuffer();
        if (param instanceof String) {
            return (String) param;
        }
        if (param instanceof JSONObject) {
            if (contentType == ContentType.APPLICATION_JSON) {
                return ((JSONObject) param).toJSONString();
            } else {
                for (String key : ((JSONObject) param).keySet()) {
                    if (((JSONObject) param).get(key) != null) {
                        paramStr.append(key).append("=").append(((JSONObject) param).get(key));
                        paramStr.append("&");
                    }
                }
            }
        }
        return paramStr.toString().length() > 0 ?
                paramStr.toString().substring(0, paramStr.toString().length() - 1) : paramStr.toString();
    }

    /**
     * 结果数据封装
     *
     * @param connection http连接
     * @return 结果数据
     * @throws IOException IO异常
     */
    private static String getHttpRequestResult(HttpURLConnection connection) throws IOException {
        // 存放数据
        StringBuffer sbf = new StringBuffer();
        InputStream is = null;
        BufferedReader br = null;
        try {
            is = connection.getInputStream();
            // 封装输入流is，并指定字符集
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            String temp;
            while ((temp = br.readLine()) != null) {
                sbf.append(temp);
                sbf.append("\r\n");
            }
        } catch (IOException ex) {
            throw new UnknownServiceException("protocol doesn't support input");
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sbf.toString();

    }

//    public static void main(String[] args) {
//        JSONObject param = new JSONObject();
//        param.put("userName", "13905437251");
//        param.put("password", "1234526");
//        String url = "http://39.107.24.230:8020//ChinaAPP/LoginController/login";
//        System.out.println(sentHttpRequest(url, RequestMethod.POST, param)
//        );
//
//    }
}
